#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<gmp.h>
#include<time.h>


int main(void)
{
    /*
	Variáveis da biblioteca time.h, para medir o tempo de execução do programa.
    */	
	time_t begin, end;
    //Pega o tempo de iníico

    time(&begin);

    /*
        10 000 000 * log2(10)
        Precisao minima para calcular a precisao de 10 milhoes de digitos
    */

    mpf_set_default_prec(33219280);

    /*
        Declaracao de Variaveis mpf_t para precisao float da biblioteca GMP
    */
    double dif_time;
    int count = 0;
    long int temp;
    mpf_t y_curr;
    mpf_t y_next;
    mpf_t a_curr;
    mpf_t a_next;
    mpf_t pi_curr;
    mpf_t pi_prev;
    mpf_t y_temp;
    mpf_t a_temp;
    mpf_t a_temp1;

    /*
        Inicializacao de Variaveis
    */
    mpf_init (y_curr);
    mpf_init (y_next);
    mpf_init (a_curr);
    mpf_init (a_next);
    mpf_init (pi_curr);
    mpf_init (pi_prev);
    mpf_init (y_temp);
    mpf_init (a_temp);
    mpf_init (a_temp1);

    mpf_set_ui (pi_curr, 1);
    mpf_set_ui (pi_prev, 0);
    
    /*
        y_curr = ((sqrt(2))-1)
    */
    mpf_sqrt_ui(y_curr,2);
    mpf_sub_ui(y_curr,y_curr,1);

    /*
        a_curr = (6-(4*sqrt(2)))
    */
    mpf_sqrt_ui(a_curr,2);
    mpf_mul_ui(a_curr, a_curr,4);
    mpf_ui_sub(a_curr,6,a_curr);


    // Enquanto a precisao do numero pi nao variar da sua precisao anterior
    while(mpf_cmp(pi_curr,pi_prev)!=0)
    {
        //atualiza o pi anterior
	mpf_set(pi_prev,pi_curr);        
        /*
            y_next =(1 - pow((1-pow(y_curr, 4)),0.25))/(1 + pow((1-pow(y_curr, 4)),0.25));
        */
        //y_temp = (1 + pow((1-pow(y_curr, 4)),0.25))
        mpf_pow_ui(y_temp,y_curr,4);
        mpf_ui_sub(y_temp,1,y_temp);
        mpf_sqrt(y_temp,y_temp);
        mpf_sqrt(y_temp,y_temp);
        mpf_add_ui(y_temp,y_temp, 1);
        //y_curr = (1 - pow((1-pow(y_curr, 4)),0.25))
        mpf_pow_ui(y_curr,y_curr,4);
        mpf_ui_sub(y_curr,1,y_curr);
        mpf_sqrt(y_curr,y_curr);
        mpf_sqrt(y_curr,y_curr);
        mpf_ui_sub(y_curr,1,y_curr);
        //y_next = y_curr/y_temp
        mpf_div(y_next,y_curr,y_temp);

        /*
        a_next = (a_curr * pow((1+y_next),4))-(pow(2,((2*count)+3)*y_next*(1+y_next+pow(y_next,2)));
        */
        //a_temp = y_next*(1+y_next+pow(y_next,2));
        mpf_pow_ui(a_temp,y_next,2);
        mpf_add(a_temp,y_next,a_temp);
        mpf_add_ui(a_temp,a_temp, 1);
        mpf_mul(a_temp,y_next,a_temp);
        //temp = pow(2,((2*count)+3);
        temp = 2*count +3;
        temp = pow(2,temp);
        //a_temp = a_temp+a_temp1;
        mpf_mul_ui(a_temp,a_temp,temp);
        //a_curr = a_curr * pow((1+y_next),4);
        mpf_add_ui(a_temp1,y_next,1);
        mpf_pow_ui(a_temp1,a_temp1,4);
        mpf_mul(a_curr,a_curr,a_temp1);
        //a_next = a_curr*a_temp;
        mpf_sub(a_next,a_curr,a_temp);

        /* Atualizacao de Variaveis */
        mpf_set(y_curr, y_next);
        mpf_set(a_curr, a_next);
	mpf_ui_div(a_temp,1, a_curr);	
        mpf_set(pi_curr, a_temp);
	
        count++;
    }
    //Pega o tempo final
    time(&end);
    // Calcula a diferença entre o tempo inicial e final
    dif_time=difftime (end,begin);
    
    printf("Quantidade iteracoes: %.d\n\n",count);
    printf("Tempo total: %lf segundos.\n\n", dif_time);
    gmp_printf("pi = %.10000000Ff",pi_curr);

    /* Libera memoria utilizada */
    mpf_clears(y_curr, y_next, a_curr, a_next, y_temp, a_temp, a_temp1, pi_curr, pi_prev, NULL);

return 0;
}
